import { describe, expect, it } from 'vitest';
import { generatePythonToolkitSources } from 'src/generation/python/generate-toolkit-sources';
import { createToolkitIndex } from 'src/generation/create-toolkit-index';
import { BANNER } from 'src/generation/constants';
import { makeTestToolkits } from 'test/__utils__/models/toolkits';
import { assertPythonIsValid } from 'test/__utils__/python-compiler';
import { TRIGGER_TYPES_GMAIL } from 'test/__mocks__/trigger-types-gmail';
import { TOOLS_GMAIL } from 'test/__mocks__/tools-gmail';

describe('generatePythonToolkitSources', () => {
  it('[Given] empty toolkits, tools, triggerTypes [Then] it returns an empty array', () => {
    const index = createToolkitIndex({
      toolkits: [],
      typeableTools: { withTypes: false, tools: [] },
      triggerTypes: [],
    });

    const sources = generatePythonToolkitSources(BANNER)(index);

    expect(sources).toEqual([]);
  });

  it('[Given] a single toolkit with no tools or triggerTypes [Then] it returns a single Python source file', () => {
    const toolkits = makeTestToolkits([
      {
        name: 'Slack Helper',
        slug: 'slack',
      },
    ]);

    const index = createToolkitIndex({
      toolkits,
      typeableTools: { withTypes: false, tools: [] },
      triggerTypes: [],
    });

    const sources = generatePythonToolkitSources(BANNER)(index);
    expect(sources).toHaveLength(1);
    expect(sources[0]).toHaveLength(2);
    expect(sources[0][0]).toBe('slack.py');
    expect(sources[0][1]).toMatchInlineSnapshot(`
      "# Auto-generated by Composio CLI. Do not modify manually..

      class SLACK:
          """Map of Composio's SLACK toolkit."""

          slug: str = "slack"

          class tools:
              pass

          class triggers:
              pass
      "
    `);

    assertPythonIsValid({ files: Object.fromEntries(sources) });
  });

  it('[Given] toolkits with tools and triggerTypes [Then] it returns a Python source file for each toolkit', () => {
    const toolkits = makeTestToolkits([
      {
        name: 'Gmail',
        slug: 'gmail',
      },
      {
        name: 'Slack Helper',
        slug: 'slack',
      },
    ]);

    const index = createToolkitIndex({
      toolkits,
      typeableTools: { withTypes: false, tools: [...TOOLS_GMAIL.slice(0, 3)] },
      triggerTypes: [...TRIGGER_TYPES_GMAIL],
    });

    const sources = generatePythonToolkitSources(BANNER)(index);
    expect(sources).toHaveLength(2);

    expect(sources[0]).toHaveLength(2);
    expect(sources[0][0]).toBe('gmail.py');
    expect(sources[0][1]).toMatchInlineSnapshot(`
      "# Auto-generated by Composio CLI. Do not modify manually..

      class GMAIL:
          """Map of Composio's GMAIL toolkit."""

          slug: str = "gmail"

          class tools:
              ADD_LABEL_TO_EMAIL = "GMAIL_ADD_LABEL_TO_EMAIL"
              CREATE_EMAIL_DRAFT = "GMAIL_CREATE_EMAIL_DRAFT"
              CREATE_LABEL = "GMAIL_CREATE_LABEL"

          class triggers:
              NEW_GMAIL_MESSAGE = {
                "config": {
                  "properties": {
                    "interval": {
                      "default": 1,
                      "description": "Periodic Interval to Check for Updates & Send a Trigger in Minutes",
                      "title": "Interval",
                      "type": "number"
                    },
                    "labelIds": {
                      "default": "INBOX",
                      "description": "Filter messages by a single label ID. Labels identify the status or category of messages. Supported labels include 'INBOX', 'SPAM', 'TRASH', 'UNREAD', 'STARRED', 'IMPORTANT', 'CATEGORY_PERSONAL', 'CATEGORY_SOCIAL', 'CATEGORY_PROMOTIONS', 'CATEGORY_UPDATES', and 'CATEGORY_FORUMS'. For complex label filtering, use the 'query' parameter instead.",
                      "examples": ["INBOX", "UNREAD", "STARRED"],
                      "title": "Labelids",
                      "type": "string"
                    },
                    "query": {
                      "default": "",
                      "description": "Advanced Gmail search using the same syntax as Gmail's search box. Use 'AND' for messages that match all conditions, 'OR' for any condition. Search by sender (from:email@domain.com), labels (label:inbox), status (is:unread), attachments (has:attachment), dates (after:2023/1/1), and more. If specified, this takes precedence over labelIds.",
                      "examples": ["label:inbox OR label:sent", "from:example@gmail.com is:unread", "has:attachment after:2023/1/1", "is:important is:unread"],
                      "title": "Query",
                      "type": "string"
                    },
                    "userId": {
                      "default": "me",
                      "description": "The user's email address or 'me' for the authenticated user.",
                      "examples": ["me"],
                      "title": "Userid",
                      "type": "string"
                    }
                  },
                  "title": "NewMessageConfig",
                  "type": "object"
                },
                "description": "Triggers when a new message is received in Gmail.",
                "instructions": "\\n    **Instructions for Setting Up the Trigger:**\\n\\n    - Ensure that the Gmail API is enabled for your Google account.\\n    - Provide the user ID (usually 'me' for the authenticated user).\\n    - Optionally, provide label IDs to filter messages.\\n    ",
                "name": "New Gmail Message Received Trigger",
                "payload": {
                  "properties": {
                    "attachment_list": {
                      "anyOf": [{
                          "items": {},
                          "type": "array"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The list of attachments in the message",
                      "title": "Attachment List"
                    },
                    "message_id": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The message ID of the message",
                      "title": "Message ID"
                    },
                    "message_text": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The text of the message",
                      "title": "Message Text"
                    },
                    "message_timestamp": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The timestamp of the message",
                      "title": "Message Timestamp"
                    },
                    "payload": {
                      "anyOf": [{
                          "type": "object"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The payload of the message",
                      "title": "Payload"
                    },
                    "sender": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The sender of the message",
                      "title": "Sender"
                    },
                    "subject": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The subject of the message",
                      "title": "Subject"
                    },
                    "thread_id": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The thread ID of the message",
                      "title": "Thread ID"
                    },
                    "to": {
                      "anyOf": [{
                          "type": "string"
                        }, {
                          "type": "null"
                        }],
                      "default": None,
                      "description": "The recipient of the message",
                      "title": "To"
                    }
                  },
                  "title": "NewMessagePayload",
                  "type": "object"
                },
                "slug": "GMAIL_NEW_GMAIL_MESSAGE",
                "type": "poll"
              }
      "
    `);

    expect(sources[1]).toHaveLength(2);
    expect(sources[1][0]).toBe('slack.py');
    expect(sources[1][1]).toMatchInlineSnapshot(`
      "# Auto-generated by Composio CLI. Do not modify manually..

      class SLACK:
          """Map of Composio's SLACK toolkit."""

          slug: str = "slack"

          class tools:
              pass

          class triggers:
              pass
      "
    `);

    assertPythonIsValid({ files: Object.fromEntries(sources) });
  });
});
